
#ifndef MORE_HH
#define MORE_HH
#include <click/element.hh>
#include <click/notifier.hh>
#include <click/ipaddress.hh>
#include <click/straccum.hh>
#include <click/packet.hh>
#include <click/etheraddress.hh>
#include <click/timer.hh>
#include "moreflow.hh"

CLICK_DECLS
/*
 * =c
 * MORE
 * =s More
 * Multipath Opportunistic Routing Engine
 *
 * =d
 * Input 0: FromDevice
 * Input 1: TX feedback
 * Input 2: ToDevice (signal to preEncode)
 * Output 0: Encoded ToDevice
 * Output 1: Acks
 * Output 2: ToHost (optional) -> route through some AverageCounter for thruput
 * Output 3: Direct ACK -> route to a UDP Socket or something
*/

class MORE : public Element {
    public:
        MORE() {}
        ~MORE() {}

        const char *class_name() const { return "MORE"; }
        const char *port_count() const { return "3/2-3"; } 
        /** 
         * h in 0  == RX packets
         * h in 1  == TX feedback
         * h in 2  == sent() signal
         * l out 0 == TX DATA packets
         * l out 1 == TX control packets
         * h out 2 == received packets
         */
        const char *processing() const { return "hhh/llh"; }
        void *cast(const char *n) {
            if (strcmp(n, "MORE") == 0)
                return (MORE *) this;
            else
                return 0;
        }

        void push(int, Packet *);
        Packet *pull(int);

        int configure(Vector<String> &, ErrorHandler *);
        int initialize(ErrorHandler *) { return 0; }

        void add_handlers();

    protected:
    // process a MORE DATA packet
        void processDATA(MOREFlow &fs, Packet *p);
    // special case at destination (p starts at more_block)
        bool dst_processDATA(MOREFlow &fs, Packet *p, MOREBatch *b);
    // when a batch is decoded output it on port 1
        void output_batch(MOREBatch *b);

        EtherAddress _eth;
        uint _data_eth_type;
        uint _ack_eth_type; // ack packet has special eth type

    // logging facilities
        FILE *_log;
        timeval _log_start;

        StringAccum _log_sa;
    // just set the start time
        void log_start() {
            if(_log) {
                click_gettimeofday(&_log_start);
                _log_sa.clear();
            }
        }
        void log_pkt(const click_ether* pkt);
        template<class T>
        void log(T s) { if(_log) _log_sa << s; }
    // log the coded block
        void log_data(const MOREBatch *batch, bool teacher, bool useful);
    // compute total time and output
        void log_end();

        void flush_log() {
            if(_log) {
                fprintf(_log, "--checkpoint\n"); // will cause logn.py to break
                fflush(_log);
            }
        }

    // NOTE: For now we have one single flowstate
        MOREFlow _one;

    public:
        EtherAddress eth() const { return _eth; }

        static int write_param(const String &, Element *, void *vparam,
                               ErrorHandler *);
};
CLICK_ENDDECLS
#endif // MORE_HH
